/*
 * Vector.cs
 * 
 * Copyright (c) 2005, dnAnalytics. All rights reserved.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using dnAnalytics.Exceptions;
using dnAnalytics.Resources;

namespace dnAnalytics.LinearAlgebra
{
    /// <summary>
    /// Abstract vector class.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
    public abstract class Vector : IFormattable, IEnumerable<KeyValuePair<int, double>>, ICloneable
    {
        #region Fields
        private int count;
        #endregion Fields

        #region Properties
        /// <summary>
        /// The number of elements in this vector.
        /// </summary>
        public int Count
        {
            get
            {
                return count;
            }
        }

        /// <summary>Indexer gets or sets the value at the given <paramref name="index"/>.</summary>
        /// <param name="index">the index of the value to get or set.</param>
        /// <returns>The value of the vector at the given <paramref name="index"/>.</returns> 
        /// <exception cref="IndexOutOfRangeException">It <paramref name="index"/> is negative or 
        /// greater than the size of the vector.</exception>
        public abstract double this[int index] { get; set; }

        #endregion Properties

        #region Protected Methods
        /// <summary>
        /// Constructs a <b>Vector</b> with the given size.
        /// </summary>
        /// <param name="size">The size of the <b>Vector</b> to construct.</param>
        /// <exception cref="ArgumentException">If <paramref name="size"/> is negative.</exception>
        protected Vector(int size)
        {
            if (size < 1)
            {
                throw new ArgumentException(Strings.NotPositiveException, "length");
            }
            count = size;
        }

        /// <summary>
        /// Creates a <b>Vector</b> of the given size;
        /// </summary>
        /// <param name="size">The size of the <b>Vector</b> to create.</param>
        /// <returns>The new <b>Vector</b>.</returns>
        protected abstract Vector CreateVector(int size);
        #endregion Protected Methods

        #region Public Methods

        /// <summary>Calculates the infinity norm of this vector.</summary>
        /// <returns>The infinity norm of this vector.</returns>  
        public virtual double InfinityNorm()
        {
            double ret = 0;
            for (int i = 0; i < Count; i++)
            {
                ret = System.Math.Max(ret, System.Math.Abs(this[i]));
            }
            return ret;
        }

        /// <summary>Calculates the L1 norm of this vector.</summary>
        /// <returns>The L1 norm of this vector.</returns>        
        public virtual double L1Norm()
        {
            double ret = 0;
            for (int i = 0; i < Count; ++i)
            {
                ret += System.Math.Abs(this[i]);
            }
            return ret;
        }

        /// <summary>Calculates the L2 norm of this vector.</summary>
        /// <returns>The L2 norm of this vector.</returns>        
        public virtual double L2Norm()
        {
            double ret = 0;
            for (int i = 0; i < Count; ++i)
            {
                ret += this[i] * this[i];
            }
            return System.Math.Sqrt(ret);
        }

        /// <summary>
        /// Returns the value of the absolute maximum element.
        /// </summary>
        /// <returns>The value of the absolute maximum element.</returns>
        public virtual double AbsoluteMaximum()
        {
            return System.Math.Abs(this[AbsoluteMaximumIndex()]);
        }

        /// <summary>
        /// Returns the index of the absolute maximum element.
        /// </summary>
        /// <returns>The index of absolute maximum element.</returns>        
        public virtual int AbsoluteMaximumIndex()
        {
            int index = 0;
            double max = System.Math.Abs(this[index]);
            for (int i = 1; i < Count; i++)
            {
                double test = System.Math.Abs(this[i]);
                if (test > max)
                {
                    index = i;
                    max = test;
                }
            }
            return index;
        }

        /// <summary>
        /// Returns the value of the absolute minimum element.
        /// </summary>
        /// <returns>The value of the absolute minimum element.</returns>
        public virtual double AbsoluteMinimum()
        {
            return System.Math.Abs(this[AbsoluteMinimumIndex()]);
        }

        /// <summary>
        /// Returns the index of the absolute minimum element.
        /// </summary>
        /// <returns>The index of absolute minimum element.</returns>        
        public virtual int AbsoluteMinimumIndex()
        {
            int index = 0;
            double min = System.Math.Abs(this[index]);
            for (int i = 1; i < Count; i++)
            {
                double test = System.Math.Abs(this[i]);
                if (test < min)
                {
                    index = i;
                    min = test;
                }
            }
            return index;
        }

        /// <summary>
        /// Returns the value of maximum element.
        /// </summary>
        /// <returns>The value of maximum element.</returns>        
        public virtual double Maximum()
        {
            return this[MaximumIndex()];
        }

        /// <summary>
        /// Returns the index of the absolute maximum element.
        /// </summary>
        /// <returns>The index of absolute maximum element.</returns>          
        public virtual int MaximumIndex()
        {
            int index = 0;
            double max = this[0];
            for (int i = 1; i < Count; i++)
            {
                if (max < this[i])
                {
                    index = i;
                    max = this[i];
                }
            }
            return index;
        }

        /// <summary>
        /// Returns the value of the minimum element.
        /// </summary>
        /// <returns>The value of the minimum element.</returns>
        public virtual double Minimum()
        {
            return this[MinimumIndex()];
        }

        /// <summary>
        /// Returns the index of the minimum element.
        /// </summary>
        /// <returns>The index of minimum element.</returns>  
        public virtual int MinimumIndex()
        {
            int index = 0;
            double min = this[0];
            for (int i = 1; i < Count; i++)
            {
                if (min > this[i])
                {
                    index = i;
                    min = this[i];
                }
            }
            return index;
        }

        /// <summary>
        /// Sets the each element to zero.
        /// </summary>
        public virtual void Clear()
        {
            for (int i = 0; i < Count; i++)
            {
                this[i] = 0;
            }
        }

        /// <summary>
        /// Copies the values of this vector into the target vector.
        /// </summary>
        /// <param name="target">The vector to copy elements into.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="target"/> is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <paramref name="target"/> is not the same size as this vector.</exception>
        public virtual void CopyTo(Vector target)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target", Strings.NullParameterException);
            }
            if (this.Count != target.Count)
            {
                throw new NotConformableException("target", Strings.ParameterNotConformable);
            }
            for (int i = 0; i < Count; i++)
            {
                target[i] = this[i];
            }
        }

        ///<summary>Computes the dot product of this vector with itself.</summary>
        ///<returns>The dot product of this vector and itself.</returns>
        public virtual double DotProduct()
        {
            return DotProduct(this);
        }

        /// <summary>Computes the dot product of this vector with another.</summary>
        /// <param name="other">The vector to compute the dot product with.</param>
        /// <returns>The dot product of this vector and other.</returns>
        /// <exception cref="ArgumentNullException">If the other vector is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If this vector  and other are not the same size.</exception>
        public virtual double DotProduct(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (this.Count != other.Count)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            double result = 0;
            for (int i = 0; i < Count; i++)
            {
                result += this[i] * other[i];
            }
            return result;
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/>  over a <see cref="Range"/> of this vector.
        /// </summary>
        /// <param name="range">The range of elements to enumerate over.</param>
        /// <returns>An <see cref="IEnumerator{T}"/> over a range of this vector.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range
        /// outside the vector's range. </exception>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the element index and the value 
        /// being the value of the element at that index.</remarks>
        /// <seealso cref="KeyValuePair{T,K}"/>
        /// <seealso cref="IEnumerator{T}"/>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerator<KeyValuePair<int, double>> GetEnumerator(Range range)
        {
            if (range.End > Count || range.Start > Count)
            {
                throw new ArgumentOutOfRangeException("range");
            }

            for (int i = range.Start; i <= range.End; i += range.Stride)
            {
                yield return new KeyValuePair<int, double>(i, this[i]);
            }
        }

        /// <summary>
        /// Creates a vector containing copy of elements for the given <see cref="Range"/>.
        /// </summary>
        /// <param name="range">The <see cref="Range"/> of elements to create a new vector from.</param>
        /// <returns>A vector containing a copy of elements for the given <see cref="Range"/>.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If the range is outside the size of the vector.</exception>        
        public virtual Vector SubVector(Range range)
        {
            if (range.End > Count || range.Start > Count)
            {
                throw new ArgumentOutOfRangeException("range");
            }

            int num = (range.End - range.Start) / range.Stride + 1;
            Vector ret = CreateVector(num);
            for (int i = range.Start, j = 0; i <= range.End; i += range.Stride, j++)
            {
                ret[j] = this[i];
            }
            return ret;
        }

        /// <summary>
        /// Computes the sum of the elements of this vector.
        /// </summary>
        /// <returns>The sum of the elements of this vector.</returns>
        public virtual double Sum()
        {
            double ret = 0;
            for (int i = 0; i < Count; i++)
            {
                ret += this[i];
            }
            return ret;
        }

        /// <summary>
        /// Computes the sum of the absolute value of the elements of this vector.
        /// </summary>
        /// <returns>The sum of the absolute value of the elements of this vector.</returns>
        public virtual double SumMagnitudes()
        {
            double ret = 0;
            for (int i = 0; i < Count; i++)
            {
                ret += System.Math.Abs(this[i]);
            }
            return ret;
        }

        /// <summary>
        /// Swaps the values of this vector with another vector.
        /// </summary>
        /// <param name="other">The vector to swap data with.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        public virtual void Swap(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }
            if (this.Count != other.Count)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                double temp = this[i];
                this[i] = other[i];
                other[i] = temp;
            }
        }

        /// <summary>
        /// Returns the data contained in the vector as an array.
        /// </summary>
        /// <returns>The data as an array.</returns>        
        public virtual double[] ToArray()
        {
            double[] ret = new double[Count];
            for (int i = 0; i < ret.Length; i++)
            {
                ret[i] = this[i];
            }
            return ret;
        }

        /// <summary>
        /// Set the values of this vector to the given values.
        /// </summary>
        /// <param name="values">The array containing the values to use.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="values"/> is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <paramref name="values"/> is not the same size as this vector.</exception>
        public virtual void SetValues(double[] values)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values", Strings.NullParameterException);
            }
            if (values.Length != Count)
            {
                throw new NotConformableException("values", Strings.ArrayParameterNotConformable);
            }
            for (int i = 0; i < values.Length; i++)
            {
                this[i] = values[i];
            }
        }

        /// <summary>
        /// Adds a scalar to each element of the vector.
        /// </summary>
        /// <param name="scalar">The scalar to add.</param>
        public virtual void Add(double scalar)
        {
            for (int i = 0; i < Count; i++)
            {
                this[i] += scalar;
            }
        }

        /// <summary>
        /// Returns a clone of this vector.
        /// </summary>
        /// <returns>A clone of this vector.</returns>
        /// <remarks>Added as an alternative to the unary addition operator.</remarks>
        public virtual Vector Plus()
        {
            return this.Clone();
        }

        /// <summary>
        /// Adds a scalar to each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to add.</param>
        /// <param name="result">The vector to store the result of the addition.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Add(double scalar, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (Count != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                result[i] = this[i] + scalar;
            }
        }

        /// <summary>
        /// Adds another vector to this vector.
        /// </summary>
        /// <param name="other">The vector to add to this one.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        public virtual void Add(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }
            if (this.Count != other.Count)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }
            for (int i = 0; i < this.Count; i++)
            {
                this[i] += other[i];
            }
        }

        /// <summary>
        /// Adds another vector to this vector and stores the result into the result vector.
        /// </summary>
        /// <param name="other">The vector to add to this one.</param>
        /// <param name="result">The vector to store the result of the addition.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <b>null</b>.</exception> 
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Add(Vector other, Vector result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (Count != other.Count)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            if (Count != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                result[i] = this[i] + other[i];
            }
        }

        /// <summary>
        /// Negates the values of this vector.
        /// </summary>
        public virtual void Negate()
        {
            for (int i = 0; i < Count; i++)
            {
                this[i] *= -1;
            }
        }

        /// <summary>
        /// Negates the values of this vector and store the result into the result vector.
        /// </summary>
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Negate(Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (this.Count != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            this.CopyTo(result);
            result.Negate();
        }

        /// <summary>
        /// Subtracts a scalar from each element of the vector.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        public virtual void Subtract(double scalar)
        {
            Add(-scalar);
        }

        /// <summary>
        /// Subtracts a scalar from each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        /// <param name="result">The vector to store the result of the subtraction.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Subtract(double scalar, Vector result)
        {
            Add(-scalar, result);
        }

        /// <summary>
        /// Subtracts another vector from this vector.
        /// </summary>
        /// <param name="other">The vector to subtract from this one.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        public virtual void Subtract(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }
            if (Count != other.Count)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                this[i] -= other[i];
            }
        }

        /// <summary>
        /// Subtracts another vector from this vector and stores the result into the result vector.
        /// </summary>
        /// <param name="other">The vector to subtract from this one.</param>
        /// <param name="result">The vector to store the result of the subtraction.</param>
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Subtract(Vector other, Vector result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (Count != other.Count)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            if (Count != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                result[i] = this[i] - other[i];
            }
        }

        /// <summary>
        /// Divides this vector by scalar.
        /// </summary>
        /// <param name="scalar">The scalar to divide this vector by.</param>
        public virtual void Divide(double scalar)
        {
            Multiply(1.0 / scalar);
        }

        /// <summary>
        /// Divides this vector by scalar and store the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to divide this vector by.</param>
        /// <param name="result">The vector to store the result of the division.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Divide(double scalar, Vector result)
        {
            Multiply(1.0 / scalar, result);
        }

        /// <summary>
        /// Multiplies this vector by scalar.
        /// </summary>
        /// <param name="scalar">The scalar to multiply this vector with.</param>
        public virtual void Multiply(double scalar)
        {
            for (int i = 0; i < Count; i++)
            {
                this[i] *= scalar;
            }
        }

        /// <summary>
        /// Multiplies this vector by scalar and store the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to multiply this vector with.</param>
        /// <param name="result">The vector to store the result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Multiply(double scalar, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (Count != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                result[i] = this[i] * scalar;
            }
        }

        /// <summary>
        /// Multiplies this vector with another vector (this x other) and returns the resulting matrix.
        /// </summary>
        /// <param name="rightSide">The vector to multiply the vector with.</param>
        /// <exception cref="ArgumentNullException">If leftSide is <b>null</b>.</exception> 
        public virtual Matrix Multiply(Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            Matrix result = MatrixBuilder.CreateMatrix(Count, rightSide.Count, MatrixType.Dense);
            Multiply(rightSide, result);
            return result;
        }

        /// <summary>
        /// Multiplies this vector with another vector (this x other) and places the result into the result vector.
        /// </summary>
        /// <param name="rightSide">The vector to multiply the vector with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If rightSide is <b>null</b>.</exception> 
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If result matrix does not have the correct dimensions.</exception>
        public virtual void Multiply(Vector rightSide, Matrix result)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Rows != this.Count || result.Columns != rightSide.Count)
            {
                throw new NotConformableException("result", Strings.ResultMatrixIncorrectDimensions);
            }

            for (int i = 0; i < this.Count; i++)
            {
                for (int j = 0; j < rightSide.Count; j++)
                {
                    result[i, j] = this[i] * rightSide[j];
                }
            }
        }

        /// <summary>
        /// Returns a <seealso cref="string"/> representation of this vector.
        /// </summary>
        /// <returns>A string representation of this vector.</returns>
        public override string ToString()
        {
            return ToString(null, null);
        }

        /// <summary>
        /// Returns a <seealso cref="string"/> representation of this vector using
        /// the given format.
        /// </summary>
        /// <param name="format">The format to use.</param>
        /// <returns>A string representation of this vector.</returns>
        public virtual string ToString(string format)
        {
            return ToString(format, null);
        }

        /// <summary>
        /// Returns a <seealso cref="string"/> representation of this vector using
        /// the given <seealso cref="IFormatProvider"/>.
        /// </summary>
        /// <param name="formatProvider">The format provider to use.</param>
        /// <returns>A string representation of this vector.</returns>
        public virtual string ToString(IFormatProvider formatProvider)
        {
            return ToString(null, formatProvider);
        }

        ///<summary>A string representation of this vector.</summary>
        ///<param name="format">A format specification.</param>
        ///<param name="formatProvider">An <see cref="IFormatProvider"/> that supplies culture-specific formatting information.</param>
        ///<returns>The string representation of the value of <b>this</b> instance as specified by format and provider.</returns>
        public virtual string ToString(string format, IFormatProvider formatProvider)
        {
            StringBuilder sb = new StringBuilder("Count: ");
            sb.Append(Count).Append(Environment.NewLine);

            for (int i = 0; i < Count; i++)
            {
                sb.Append(this[i].ToString(format, formatProvider));
                if (i != Count - 1)
                {
                    sb.Append(", ");
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/>  over this vector.
        /// </summary>
        /// <returns>An <see cref="IEnumerator{T}"/> over this vector.</returns>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the element index and the value 
        /// being the value of the element at that index.</remarks>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerator<KeyValuePair<int, double>> GetEnumerator()
        {
            for (int i = 0; i < Count; i++)
            {
                yield return new KeyValuePair<int, double>(i, this[i]);
            }
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/>  over this vector.
        /// </summary>
        /// <returns>An <see cref="IEnumerator{T}"/> over this vector.</returns>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the element index and the value 
        /// being the value of the element at that index.</remarks>
        /// <include file='../../../examples/trunk/LinearAlgebra/SparseVectorEnumerator.xml' path='example'/> 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        /// Returns a deep-copy clone of the <b>Vector</b>.
        /// </summary>
        /// <returns>A deep-copy clone of the <b>Vector</b>.</returns>
        public virtual Vector Clone()
        {
            Vector ret = CreateVector(Count);
            this.CopyTo(ret);
            return ret;
        }

        /// <summary>
        /// Returns a deep-copy clone of the <b>Vector</b>.
        /// </summary>
        /// <returns>A deep-copy clone of the <b>Vector</b>.</returns>
        Object ICloneable.Clone()
        {
            return this.Clone();
        }

        #endregion Public Methods

        #region Operators

        /// <summary>
        /// Returns a <b>Vector</b> containing the same values of rightSide. 
        /// </summary>
        /// <remarks>This method is included for completeness.</remarks>
        /// <param name="rightSide">The vector to get the values from.</param>
        /// <returns>A vector containing a the same values as <paramref name="rightSide"/>.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Vector operator +(Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            return rightSide.Clone();
        }

        /// <summary>
        /// Adds two <b>Vectors</b> together and returns the results.
        /// </summary>
        /// <param name="leftSide">One of the vectors to add.</param>
        /// <param name="rightSide">One of the vectors to add.</param>
        /// <returns>The result of the addition.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> are not the same size.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Vector operator +(Vector leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (leftSide.Count != rightSide.Count)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }

            Vector ret = leftSide.Clone();
            ret.Add(rightSide);
            return ret;
        }

        /// <summary>
        /// Negates each element of the vector.
        /// </summary>
        /// <param name="rightSide">The vector to negate.</param>
        /// <returns>A vector containing the negated values.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Vector operator -(Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            Vector ret = rightSide.Clone();
            ret.Negate();
            return ret;
        }

        /// <summary>
        /// Subtracts two vectors and returns the results.
        /// </summary>
        /// <param name="leftSide">The vector to subtract from.</param>
        /// <param name="rightSide">The vector to subtract.</param>
        /// <returns>The result of the subtraction.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> are not the same size.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Vector operator -(Vector leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (leftSide.Count != rightSide.Count)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }
            Vector ret = leftSide.Clone();
            ret.Subtract(rightSide);
            return ret;
        }

        /// <summary>
        /// Divides a <b>Vector</b> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The vector to divide.</param>
        /// <param name="rightSide">The constant to divide the vector by.</param>
        /// <returns>The result of the division.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <b>null</b>.</exception>
        public static Vector operator /(Vector leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            Vector ret = leftSide.Clone();
            ret.Divide(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <b>Vector</b> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The vector to multiply.</param>
        /// <param name="rightSide">The constant to multiply the vector by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Vector operator *(double leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            Vector ret = rightSide.Clone();
            ret.Multiply(leftSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <b>Vector</b> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The vector to multiply.</param>
        /// <param name="rightSide">The constant to multiply the vector by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <b>null</b>.</exception>
        public static Vector operator *(Vector leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }
            Vector ret = leftSide.Clone();
            ret.Multiply(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiples two <b>Vectors</b>. The first vector is treated as column vector and
        /// the second as row vector.
        /// </summary>
        /// <param name="leftSide">One of the vectors to multiply.</param>
        /// <param name="rightSide">One of the vectors to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Matrix operator *(Vector leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }
            return leftSide.Multiply(rightSide);
        }

        #endregion Operators
    }
}
